﻿using DX.Security;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Linq;

namespace Tools.Plugins.Auths
{
    class ADUserProfile : IUserProfile
    {

        public ADUserProfile(object id, string name, string displayName, IDictionary<string, object> properties = null)
        {
            ID = id;
            Name = name;
            DisplayName = displayName;
            Properties = properties;
        }
        public object ID { get; }

        public string Name { get; }
        public string DisplayName { get; }

        public IDictionary<string, object> Properties { get; }
    }
    public class ADOption
    {
        public string DomainName { get; set; }
        public string Account { get; set; }
        public string Password { get; set; }


    }
    class ADAuthProvider : IAuthProvider
    {

        public ADAuthProvider(IOptions<ADOption> option)
        {
            this.option = option.Value;
        }
        private readonly ADOption option;
        public bool ValidateCredentials(string account, string password)
        {
            using var directoryContext = new PrincipalContext(ContextType.Domain, option.DomainName);
            return directoryContext.ValidateCredentials(account, password);
        }

        public void ChangePassword(string account, string oldpassword, string newpassword)
        {
            try
            {
                using var directoryContext = new PrincipalContext(ContextType.Domain, option.DomainName, account, oldpassword);
                using var finduser = UserPrincipal.FindByIdentity(directoryContext, IdentityType.SamAccountName, account);
                if (finduser == null) return;
                finduser.ChangePassword(oldpassword, newpassword);
            }
            catch (DirectoryServicesCOMException e)
            {
                throw new AuthException(e.Message, e);
            }
            catch (Exception e)
            {

                throw new AuthException("修改密码失败", e);
            }
        }

        public IUserProfile FindUser(string account)
        {
            try
            {
                using var directoryContext = new PrincipalContext(ContextType.Domain, option.DomainName, option.Account, option.Password);
                using var finduser = UserPrincipal.FindByIdentity(directoryContext, IdentityType.SamAccountName, account);
                if (finduser == null) return null;
                var entry = finduser.GetUnderlyingObject() as DirectoryEntry;
                return new ADUserProfile(finduser.Sid, finduser.Name, finduser.DisplayName, entry.Properties.OfType<PropertyValueCollection>().ToDictionary(n => n.PropertyName, n => n.Value));
            }
            catch (DirectoryServicesCOMException e)
            {
                throw new AuthException(e.Message, e);
            }
            catch (Exception e)
            {

                throw new AuthException("查找用户失败", e);
            }
        }
        public bool Exist(string account)
        {
            try
            {
                using var directoryContext = new PrincipalContext(ContextType.Domain, option.DomainName, option.Account, option.Password);
                var finduser = UserPrincipal.FindByIdentity(directoryContext, IdentityType.SamAccountName, account);
                return finduser != null;
            }
            catch (DirectoryServicesCOMException e)
            {
                throw new AuthException(e.Message, e);
            }
            catch (Exception e)
            {

                throw new AuthException("查找用户失败", e);
            }
        }


    }
}
